<?php
namespace App\Model;

use App\Utility\BaseException;
use App\Server\PoolServer\RedisPool;
// use EasySwoole\Core\Swoole\Coroutine\PoolManager;
use EasySwoole\Core\Swoole\Coroutine\Client\Redis as CoroutineRedis;
use EasySwoole\Config;
use EasySwoole\Core\Component\Pool\PoolManager;

class Redis
{

    private $pool;

    private $prefix = "chat_";

    private $handler;

    public function __construct()
    {}

    function getRedis()
    {
        try {
            $pool = PoolManager::getInstance()->getPool(RedisPool::class);
            if (empty($pool)) {
                throw new BaseException([
                    "code" => 000020,
                    "msg" => "redis pool 异常"
                ]);
            }
            $this->pool = $pool;
            $obj = $this->pool->getObj();
            if (empty($obj)) {
                throw new BaseException([
                    "code" => 000021,
                    "msg" => "redis obj 获取失败"
                ]);
            }
            $this->handler = $obj;
        } catch (\Exception $e) {
            $conf = Config::getInstance()->getConf('REDIS');
            $this->handler = new CoroutineRedis($conf['host'], $conf['port'], $conf['serialize'], $conf['auth']);
            if (is_callable($conf['errorHandler'])) {
                $this->handler->setErrorHandler($conf['errorHandler']);
            }
        }
    }

    /**
     * 读取缓存
     *
     * @access public
     * @param string $name
     *            缓存变量名
     * @param mixed $default
     *            默认值
     * @return mixed
     */
    public function get($name, $default = false)
    {
        $name = $this->prefix . $name;
        $value = $this->handler->exec("get", $name);
        if (is_null($value)) {
            return $default;
        }
        $jsonData = json_decode($value, true);
        // 检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 byron sampson<xiaobo.sun@qq.com>
        return (null === $jsonData) ? $value : $jsonData;
    }

    /**
     * 写入缓存
     *
     * @access public
     * @param string $name
     *            缓存变量名
     * @param mixed $value
     *            存储数据
     * @param integer $expire
     *            有效时间（秒）
     * @return boolean
     */
    public function set($name, $value, $expire = 86400)
    {
        $name = $this->prefix . $name;
        // 对数组/对象数据进行缓存处理，保证数据完整性 byron sampson<xiaobo.sun@qq.com>
        $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;
        $result = $this->handler->exec('set', $name, $value);
        if ($expire > 0) {
            $this->handler->exec("EXPIRE", $name, $expire);
        }
        return $result;
    }

    public function del($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('del', $key);
        return $res;
    }

    /**
     * 自增+1
     *
     * @access public
     * @param string $name
     *            缓存变量名
     * @param mixed $value
     *            存储数据
     * @param integer $expire
     *            有效时间（秒）
     * @return boolean
     */
    public function incr($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('incr', $key);
        return $res;
    }

    /**
     * 自减 -1
     *
     * @access public
     * @param string $name
     *            缓存变量名
     * @param mixed $value
     *            存储数据
     * @param integer $expire
     *            有效时间（秒）
     * @return boolean
     */
    public function decr($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('decr', $key);
        return $res;
    }

    /*
     * hash 集合操作
     */
    /**
     * 为hash表多个字段设定值。
     *
     * @param string $key            
     * @param array $value            
     * @return array|bool
     */
    public function hMset($key, array $value, $expire = 86400)
    {
        $key = $this->prefix . $key;
        
        $res = $this->handler->exec('hMset', $key, $value);
        if ($expire >= 0) {
            $this->handler->exec("EXPIRE", $key, $expire);
        }
        return $res;
    }

    /**
     * 为hash表多个字段设定值。
     *
     * @param string $key            
     * @param
     *            array
     *            
     * @return array|bool
     */
    public function hMget($key, array $field)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('hMget', $key, $field);
        return $res;
    }

    /**
     * 为hash表设定一个字段的值
     *
     * @param string $key
     *            缓存key
     * @param string $field
     *            字段
     * @param string $value
     *            值。
     * @return bool
     */
    public function hSet($key, $field, $value, $expire = 86400)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('hSet', $key, $field, $value);
        if ($expire >= 0) {
            $this->handler->exec("EXPIRE", $key, $expire);
        }
        return $res;
    }

    /**
     * 得到hash表中一个字段的值
     *
     * @param string $key
     *            缓存key
     * @param string $field
     *            字段
     * @return string|false
     */
    public function hGet($key, $field)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('hGet', $key, $field);
        
        return $res;
    }

    /**
     * 返回所有hash表的字段值，为一个关联数组
     *
     * @param string $key            
     * @return array|bool
     */
    public function hGetAll($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('hGetAll', $key);
        $flag = 1;
        $data = [];
        $tmp = [];
        if ($res) {
            foreach ($res as $key => $val) {
                if ($flag % 2 == 0) {
                    $tmp_key = array_pop($tmp);
                    $data[$tmp_key] = $val;
                } else {
                    array_push($tmp, $val);
                }
                $flag += 1;
            }
        }
        return $data;
    }

    /**
     * 返回所有hash表的所有字段
     *
     * @param string $key            
     * @return array|bool
     */
    public function hKeys($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('hKeys', $key);
        return $res;
    }

    public function hDel($key, $hashKey)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('hDel', $key, $hashKey);
        return $res;
    }

    public function hDelAll($key)
    {
        $field = $this->hKeys($key);
        $delNum = 0;
        if ($field) {
            foreach ($field as $k => $v) {
                $v = trim($v);
                $delNum += $this->hDel($key, $v);
            }
        }
        return $delNum;
    }

    /**
     * 返回hash表元素个数
     *
     * @param string $key
     *            缓存key
     * @return int|bool
     */
    public function hLen($key)
    {
        $key = $this->prefix . $key;
        return $this->handler->exec('hLen', $key);
    }

    /*
     * 添加一个集合成员
     */
    public function sAdd($key, $value = [])
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('sAdd', $key, $value);
        return $res;
    }

    /*
     * 获取集合的成员数
     */
    public function sCard($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('sCard', $key);
        return $res;
    }

    /*
     * 删除一个集合成员
     */
    public function sRem($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('sRem', $key);
        return $res;
    }

    /*
     * 获取集合的所有成员
     */
    public function sMembers($key)
    {
        $key = $this->prefix . $key;
        $res = $this->handler->exec('sMembers', $key);
        return $res;
    }

    public function free()
    {
        if ($this->pool) {
            $this->pool->freeObj($this->handler);
        }
    }
}